package cn.demoncat.util.mybatis.plus;

import cn.demoncat.util.lang.ArrayUtil;
import cn.demoncat.util.lang.CollectionUtil;
import cn.demoncat.util.lang.CollectorUtil;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.constant.StatusConstant;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.mybatis.constant.MapperConstant;
import cn.demoncat.util.mybatis.param.CreateTime;
import cn.demoncat.util.mybatis.param.UpdateTime;
import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.enums.SqlKeyword;
import com.baomidou.mybatisplus.core.enums.SqlLike;
import com.baomidou.mybatisplus.core.toolkit.SerializationUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.baomidou.mybatisplus.core.enums.SqlKeyword.EQ;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.NE;
import static com.baomidou.mybatisplus.core.enums.WrapperKeyword.APPLY;

/**
 * 查询条件
 *
 * 1、如果参数为null或''，忽略
 *
 * @author 延晓磊
 * @since 2021年08月27日
 */
public class Query<T> extends QueryWrapper<T> {

    // 是否支持驼峰参数
    private boolean supportHumpParam;

    /**
     * 空条件
     *
     * @param <T>
     * @return
     */
    public static <T> Query<T> empty() {
        return new Query<>();
    }

    /**
     * 获取lambda式Query
     *
     * 注：每次调用都会新建对象，效率低
     *
     * @return
     */
    @Override
    public LambdaQuery<T> lambda() {
        return new LambdaQuery<>(getEntity(), getEntityClass(), sqlSelect, paramNameSeq, paramNameValuePairs, expression, paramAlias, lastSql, sqlComment, sqlFirst);
    }

    /**
     * 支持驼峰参数
     *
     * 1、调用本方法后，如果参数为 xxXx ，将转为字段名 xx_xx（调用前的不会转换）
     * 2、如果字段名没有强制 xx_xx，而是允许驼峰，不要调用本方法
     *
     * @return
     */
    public Query<T> hump(){
        this.supportHumpParam = true;
        return this;
    }

    /**
     * 添加条件（不带括号）
     *
     * @param consumer
     * @return
     */
    public Query<T> add(Consumer<Query<T>> consumer){
        return add(true, consumer);
    }

    /**
     * 添加条件（不带括号）
     *
     * @param condition
     * @param consumer
     * @return
     */
    public Query<T> add(boolean condition, Consumer<Query<T>> consumer){
        if (condition) {
            consumer.accept(this);
        }
        return this;
    }

    /**
     * 添加嵌套条件（带括号）
     *
     * @param condition
     * @param consumer
     * @return
     */
    public Query<T> addNestedConditionPlus(boolean condition, Consumer<Query<T>> consumer) {
        maybeDo(condition, () -> {
            final Query<T> instance = instancePlus();
            consumer.accept(instance);
            appendSqlSegments(APPLY, instance);
        });
        return this;
    }

    /**
     * eq 条件
     * 
     * 注意：多次eq同一个column，不会替换值，而是 and 拼接多次
     *
     * @param column
     * @param val   为空时忽略，判断空须使用isEmpty或isNullEmpty
     * @return
     */
    @Override
    public Query<T> eq(String column, Object val) {
        return this.eq(true, column, val);
    }

    /**
     * eq 条件
     *
     * @param condition
     * @param column
     * @param val   为空时忽略，判断空须使用isEmpty或isNullEmpty
     * @return
     */
    @Override
    public Query<T> eq(boolean condition, String column, Object val) {
        super.eq(condition, column, val);
        return this;
    }

    /**
     * eq 条件
     *
     * @param columnAndValues   键,值...（为空时忽略，判断空须使用isEmpty或isNullEmpty）
     * @return
     */
    public Query<T> eqs(String ... columnAndValues) {
        if (ArrayUtils.isNotEmpty(columnAndValues)) {
            for (int i = 0; i < columnAndValues.length; i = i+2) {
                this.eq(columnAndValues[i], columnAndValues[i+1]);
            }
        }
        return this;
    }

    /**
     * eq 条件
     *
     * @param params    批量条件{字段名:字段值}；为空时忽略，判断空须使用isEmpty或isNullEmpty
     * @return
     */
    @Override
    public <V> Query<T> allEq(Map<String, V> params) {
        super.allEq(params, false);
        return this;
    }

    /**
     * ne 条件
     *
     * @param column
     * @param val   为空时忽略，判断空须使用isNotEmpty或isNotNullEmpty
     * @return
     */
    @Override
    public Query<T> ne(String column, Object val) {
        return this.ne(true, column, val);
    }

    /**
     * ne 条件
     *
     * @param condition
     * @param column
     * @param val   为空时忽略，判断空须使用isNotEmpty或isNotNullEmpty
     * @return
     */
    @Override
    public Query<T> ne(boolean condition, String column, Object val) {
        super.ne(condition, column, val);
        return this;
    }

    /**
     * eq 条件
     *
     * @param condition
     * @param column
     * @param sqlKeyword
     * @param val   为空时忽略，判断空须使用super.addCondition()
     * @return
     */
    @Override
    protected Query<T> addCondition(boolean condition, String column, SqlKeyword sqlKeyword, Object val) {
        if (condition && condition(val)) {
            super.addCondition(true, column, sqlKeyword, val);
        }
        return this;
    }

    /**
     * like 条件
     *
     * @param column
     * @param val       为空时忽略
     * @return '%值%'
     */
    @Override
    public Query<T> like(String column, Object val) {
        return this.like(true, column, val);
    }

    /**
     * like 条件
     *
     * @param condition
     * @param column
     * @param val       为空时忽略
     * @return '%值%'
     */
    @Override
    public Query<T> like(boolean condition, String column, Object val) {
        super.like(condition, column, val);
        return this;
    }

    /**
     * like 条件
     *
     * @param column
     * @param val       为空时忽略
     * @return '值%'
     */
    @Override
    public Query<T> likeLeft(String column, Object val) {
        return this.likeLeft(true, column, val);
    }

    /**
     * like 条件
     *
     * @param condition
     * @param column
     * @param val       为空时忽略
     * @return '值%'
     */
    @Override
    public Query<T> likeLeft(boolean condition, String column, Object val) {
        super.likeRight(condition, column, val);
        return this;
    }

    /**
     * like 条件
     *
     * @param column
     * @param val       为空时忽略
     * @return '%值'
     */
    @Override
    public Query<T> likeRight(String column, Object val) {
        return this.likeRight(true, column, val);
    }

    /**
     * like 条件
     *
     * @param condition
     * @param column
     * @param val       为空时忽略
     * @return '%值'
     */
    @Override
    public Query<T> likeRight(boolean condition, String column, Object val) {
        super.likeLeft(condition, column, val);
        return this;
    }

    /**
     * like 条件
     *
     * @param column
     * @param val       为空时忽略
     * @return
     */
    @Override
    public Query<T> notLike(String column, Object val) {
        return this.notLike(true, column, val);
    }

    /**
     * like 条件
     *
     * @param condition
     * @param column
     * @param val       为空时忽略
     * @return
     */
    @Override
    public Query<T> notLike(boolean condition, String column, Object val) {
        super.notLike(condition, column, val);
        return this;
    }

    /**
     * like 条件
     *
     * @param condition
     * @param keyword
     * @param column
     * @param val       为空时忽略
     * @param sqlLike
     * @return
     */
    @Override
    protected Query<T> likeValue(boolean condition, SqlKeyword keyword, String column, Object val, SqlLike sqlLike) {
        if (condition && condition(val)) {
            super.likeValue(true, keyword, column, val, sqlLike);
        }
        return this;
    }

    /**
     * id in查询
     *
     * @param ids    id列表。为null时忽略；为空时设随机值，让查询无结果
     * @return
     */
    public Query<T> ids(Collection<?> ids) {
        return this.in(true, "id", ids);
    }

    /**
     * id in查询 + ids排序
     *
     * @param ids    id列表。为null时忽略；为空时设随机值，让查询无结果
     * @return
     */
    public Query<T> idsAndSort(Collection<?> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return ids(ids);
        }else{
            return this.in(true, "id", ids).orderByAsc(String.format(MapperConstant.SortParam.ID_IN, ids.stream().map(StringUtil::toString).collect(CollectorUtil.joinComma())));
        }
    }

    /**
     * in查询
     *
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> in(String column, Object... values) {
        return this.in(true, column, values);
    }

    /**
     * in查询
     *
     * @param column
     * @param values    为null时忽略；为空时设随机值，让查询无结果
     * @return
     */
    @Override
    public Query<T> in(String column, Collection<?> values) {
        return this.in(true, column, values);
    }

    /**
     * in查询
     *
     * @param condition
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> in(boolean condition, String column, Object... values) {
        return this.in(condition, column, ArrayUtil.toList(values));
    }

    /**
     * in查询
     *
     * @param condition
     * @param column
     * @param values    为null时忽略；为空时设随机值，让查询无结果
     * @return
     */
    @Override
    public Query<T> in(boolean condition, String column, Collection<?> values) {
        if (condition && values != null) {
            if (values.isEmpty()) {
                // 使用随机数条件，让查询无结果
                super.eq(true, column, System.currentTimeMillis());
            }else{
                // 去重
                values = new HashSet<>(values);
                if (values.size() == 1) {
                    // 单条
                    super.eq(true, column, CollectionUtil.any(values));
                }else{
                    // 多条
                    super.in(true, column, values);
                }
            }
        }
        return this;
    }

    /**
     * IN ( sql语句 )
     *
     * 例1: inSql("id", "1, 2, 3, 4, 5, 6")
     * 例2: inSql("id", "select id from table where id < 3")
     *
     * @param column    字段
     * @param sql   sql语句
     * @return
     */
    public Query<T> inSql(String column, String sql){
        super.inSql(column, sql);
        return this;
    }

    /**
     * id not in查询
     *
     * @param ids   ID列表。为空时忽略
     * @return
     */
    public Query<T> notIds(Collection<?> ids) {
        return this.notIn(true, "id", ids);
    }

    /**
     * not in查询
     *
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> notIn(String column, Object... values) {
        return this.notIn(true, column, values);
    }

    /**
     * not in查询
     *
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> notIn(String column, Collection<?> values) {
        return this.notIn(true, column, values);
    }

    /**
     * not in查询
     *
     * @param condition
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> notIn(boolean condition, String column, Object... values) {
        if (condition && values != null && values.length > 0) {
            super.notIn(true, column, values);
        }
        return this;
    }

    /**
     * not in查询
     *
     * @param condition
     * @param column
     * @param values    为空时忽略
     * @return
     */
    @Override
    public Query<T> notIn(boolean condition, String column, Collection<?> values) {
        if (condition && values != null && values.size() > 0) {
            super.notIn(true, column, values);
        }
        return this;
    }

    /**
     * Exists
     *
     * @param sql       SQL语句，可以通过{0},{1}来占位
     * @param values    值，索引对应sql中的{0},{1}占位符
     * @return
     */
    @Override
    public Query<T> exists(String sql, Object... values) {
        return this.exists(true, sql, values);
    }

    /**
     * Exists
     *
     * @param condition
     * @param sql       SQL语句，可以通过{0},{1}来占位
     * @param values    值，索引对应sql中的{0},{1}占位符
     * @return
     */
    @Override
    public Query<T> exists(boolean condition, String sql, Object... values) {
        super.exists(condition, sql, values);
        return this;
    }

    /**
     * Not Exists
     *
     * @param sql       SQL语句，可以通过{0},{1}来占位
     * @param values    值，索引对应sql中的{0},{1}占位符
     * @return
     */
    @Override
    public Query<T> notExists(String sql, Object... values) {
        return this.notExists(true, sql, values);
    }

    /**
     * Not Exists
     *
     * @param condition
     * @param sql        SQL语句，可以通过{0},{1}来占位
     * @param values    值，索引对应sql中的{0},{1}占位符
     * @return
     */
    @Override
    public Query<T> notExists(boolean condition, String sql, Object... values) {
        super.notExists(condition, sql, values);
        return this;
    }

    /**
     * 大于
     *
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> gt(String column, Object val) {
        return this.gt(true, column, val);
    }

    /**
     * 大于
     *
     * @param condition
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> gt(boolean condition, String column, Object val) {
        super.gt(condition, column, val);
        return this;
    }

    /**
     * 大于等于
     *
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> ge(String column, Object val) {
        return this.ge(true, column, val);
    }

    /**
     * 大于等于
     *
     * @param condition
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> ge(boolean condition, String column, Object val) {
        super.ge(condition, column, val);
        return this;
    }

    /**
     * 小于
     *
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> lt(String column, Object val) {
        return this.lt(true, column, val);
    }

    /**
     * 小于
     *
     * @param condition
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> lt(boolean condition, String column, Object val) {
        super.lt(condition, column, val);
        return this;
    }

    /**
     * 小于等于
     *
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> le(String column, Object val) {
        return this.le(true, column, val);
    }

    /**
     * 小于等于
     *
     * @param condition
     * @param column
     * @param val
     * @return
     */
    @Override
    public Query<T> le(boolean condition, String column, Object val) {
        super.le(condition, column, val);
        return this;
    }

    /**
     * 区间
     *
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    @Override
    public Query<T> between(String column, Object val1, Object val2) {
        return this.between(true, column, val1, val2);
    }

    /**
     * 区间
     *
     * @param condition
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    @Override
    public Query<T> between(boolean condition, String column, Object val1, Object val2) {
        if (condition(val1) && condition(val2)) {
            super.between(condition, column, val1, val2);
        }else if (condition(val1) && !condition(val2)) {
            super.ge(condition, column, val1);
        }else if(!condition(val1) && condition(val2)){
            super.lt(condition, column, val2);
        }
        return this;
    }

    /**
     * 非区间
     *
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    @Override
    public Query<T> notBetween(String column, Object val1, Object val2) {
        return this.notBetween(true, column, val1, val2);
    }

    /**
     * 非区间
     *
     * @param condition
     * @param column
     * @param val1
     * @param val2
     * @return
     */
    @Override
    public Query<T> notBetween(boolean condition, String column, Object val1, Object val2) {
        if (condition(val1) && condition(val2)) {
            super.notBetween(condition, column, val1, val2);
        }else if (condition(val1) && !condition(val2)) {
            super.lt(condition, column, val1);
        }else if(!condition(val1) && condition(val2)){
            super.ge(condition, column, val2);
        }
        return this;
    }

    /**
     * 是null
     *
     * @param column
     * @return
     */
    @Override
    public Query<T> isNull(String column) {
        return this.isNull(true, column);
    }

    /**
     * 是null
     *
     * @param condition
     * @param column
     * @return
     */
    @Override
    public Query<T> isNull(boolean condition, String column) {
        super.isNull(condition, column);
        return this;
    }

    /**
     * 非null
     *
     * @param column
     * @return
     */
    @Override
    public Query<T> isNotNull(String column) {
        return this.isNotNull(true, column);
    }

    /**
     * 非null
     *
     * @param condition
     * @param column
     * @return
     */
    @Override
    public Query<T> isNotNull(boolean condition, String column) {
        super.isNotNull(condition, column);
        return this;
    }

    /**
     * 是''
     *
     * @param column
     * @return
     */
    public Query<T> isEmpty(String column) {
        return this.isEmpty(true, column);
    }

    /**
     * 是''
     *
     * @param condition
     * @param column
     * @return
     */
    public Query<T> isEmpty(boolean condition, String column) {
        super.addCondition(condition, column, EQ, StringConstant.EMPTY);
        return this;
    }

    /**
     * 非''
     *
     * @param column
     * @return
     */
    public Query<T> isNotEmpty(String column) {
        return this.isNotEmpty(true, column);
    }

    /**
     * 非''
     *
     * @param condition
     * @param column
     * @return
     */
    public Query<T> isNotEmpty(boolean condition, String column) {
        super.addCondition(condition, column, NE, StringConstant.EMPTY);
        return this;
    }

    /**
     * 是null或''
     *
     * @param column
     * @return
     */
    public Query<T> isNullEmpty(String column) {
        return this.isNullEmpty(true, column);
    }

    /**
     * 是null或''
     *
     * @param condition
     * @param column
     * @return
     */
    public Query<T> isNullEmpty(boolean condition, String column) {
        return this.andPlus(condition, q -> q.isNull(column).or().isEmpty(column));
    }

    /**
     * 非null或''
     *
     * @param column
     * @return
     */
    public Query<T> isNotNullEmpty(String column) {
        return this.isNotNullEmpty(true, column);
    }

    /**
     * 非null或''
     *
     * @param condition
     * @param column
     * @return
     */
    public Query<T> isNotNullEmpty(boolean condition, String column) {
        if (condition) {
            return this.isNotNull(column).isNotEmpty(column);
        }
        return this;
    }

    /**
     * FIND_IN_SET
     *
     * @param column    "1,2,3"
     * @param value     "2"
     * @return
     */
    public Query<T> findInSet(String column, String value){
        if (StringUtils.isNotBlank(value)) {
            super.apply("FIND_IN_SET({0}, "+ columnToString(column) +")", value);
        }
        return this;
    }

    /**
     * FIND_IN_SET
     *
     * @param condition
     * @param column    字段名，值为"1,2,3"格式
     * @param value     查询值
     * @return
     */
    public Query<T> findInSet(boolean condition, String column, String value){
        if (condition) {
            return this.findInSet(column, value);
        }
        return this;
    }

    /**
     * 条件 - id
     *
     * @param id
     * @return
     */
    public Query<T> id(Serializable id){
        return this.eq(MapperConstant.ColumnName.ID, id);
    }

    /**
     * 条件 - 未删除
     *
     * @return is_del = 0
     */
    public Query<T> undeleted(){
        return this.eq(MapperConstant.ColumnName.IS_DEL, StatusConstant.Common.NO);
    }

    /**
     * 条件 - 启用
     *
     * @return status = 1
     */
    public Query<T> enable(){
        return this.eq(MapperConstant.ColumnName.STATUS, StatusConstant.Common.YES);
    }

    /**
     * 条件 - create_time
     *
     * @param createTime
     * @return
     */
    public Query<T> createTime(CreateTime createTime){
        if (createTime == null) {
            return this;
        }
        return this.between("create_time", createTime.getStartCreateTime(), createTime.getEndCreateTime());
    }

    /**
     * 条件 - update_time
     *
     * @param updateTime
     * @return
     */
    public Query<T> updateTime(UpdateTime updateTime){
        if (updateTime == null) {
            return this;
        }
        return this.between("update_time", updateTime.getStartUpdateTime(), updateTime.getEndUpdateTime());
    }

    /**
     * 条件 - start <= column <= end
     *
     * @param column
     * @param start
     * @param end
     * @return
     */
    public Query<T> range(String column, Object start, Object end){
        if (start != null) {
            this.ge(column, start);
        }
        if (end != null) {
            this.le(column, end);
        }
        return this;
    }

    /**
     * 条件 - start <= column <= end
     *
     * @param column
     * @param start
     * @param end
     * @return
     */
    public Query<T> range(String column, String start, String end){
        if (StringUtils.isNotBlank(start)) {
            this.ge(column, start);
        }
        if (StringUtils.isNotBlank(end)) {
            this.le(column, end);
        }
        return this;
    }

    /**
     * 默认构造
     */
    public Query() {
        super();
    }

    /**
     * 私有构造，只用于生产嵌套 sql
     */
    private Query(T entity, Class<T> entityClass, AtomicInteger paramNameSeq, Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments, SharedString paramAlias, SharedString lastSql, SharedString sqlComment, SharedString sqlFirst) {
        super.setEntity(entity);
        super.setEntityClass(entityClass);
        this.paramNameSeq = paramNameSeq;
        this.paramNameValuePairs = paramNameValuePairs;
        this.expression = mergeSegments;
        this.paramAlias = paramAlias;
        this.lastSql = lastSql;
        this.sqlComment = sqlComment;
        this.sqlFirst = sqlFirst;
    }

    /**
     * 生成嵌套 sql
     */
    protected Query<T> instancePlus() {
        Query<T> query = new Query<>(getEntity(), getEntityClass(), paramNameSeq, paramNameValuePairs, new MergeSegments(),paramAlias, SharedString.emptyString(), SharedString.emptyString(), SharedString.emptyString());
        query.supportHumpParam = this.supportHumpParam;
        return query;
    }

    /**
     * and
     *
     * @param condition
     * @return
     */
    @Override
    public Query<T> and(boolean condition) {
        super.and(condition);
        return this;
    }

    /**
     * and
     *
     * @param consumer
     * @return
     */
    public Query<T> andPlus(Consumer<Query<T>> consumer) {
        return this.andPlus(true, consumer);
    }

    /**
     * and
     *
     * @param condition
     * @param consumer
     * @return
     */
    public Query<T> andPlus(boolean condition, Consumer<Query<T>> consumer) {
        return this.and(condition).addNestedConditionPlus(condition, consumer);
    }

    /**
     *  and (like or like)
     *
     * @param fields    字段
     * @param value     值
     * @return
     */
    public Query<T> andLikes(List<String> fields, String value){
        return andLikes(true, fields, value);
    }

    /**
     * and (like or like)
     *
     * @param condition
     * @param fields    字段
     * @param value     值
     * @return
     */
    public Query<T> andLikes(boolean condition, List<String> fields, String value){
        if (condition && condition(value)) {
            this.andPlus(q -> {
                for (String field : fields) {
                    q.or().like(field, value);
                }
            });
        }
        return this;
    }

    /**
     * or
     *
     * @return
     */
    @Override
    public Query<T> or() {
        return this.or(true);
    }

    /**
     * or
     *
     * @param condition
     * @return
     */
    @Override
    public Query<T> or(boolean condition) {
        super.or(condition);
        return this;
    }

    /**
     * or
     *
     * @param consumer
     * @return
     */
    public Query<T> orPlus(Consumer<Query<T>> consumer) {
        return this.orPlus(true, consumer);
    }

    /**
     * or
     *
     * @param condition
     * @param consumer
     * @return
     */
    public Query<T> orPlus(boolean condition, Consumer<Query<T>> consumer) {
        return this.or(condition).addNestedConditionPlus(condition, consumer);
    }

    /**
     * 查询字段
     *
     * @param columns   查询字段或函数，多次调用会替换
     * @return
     */
    @Override
    public Query<T> select(String... columns) {
        if (this.supportHumpParam && columns.length > 1) {
            super.select(Arrays.stream(columns).map(this::columnToString).toArray(o -> new String[columns.length]));
        }else{
            super.select(columns);
        }
        return this;
    }

    /**
     * LIMIT count
     *
     * @param count      返回个数
     * @return
     */
    public Query<T> limit(Integer count) {
        if (count != null && count > 0) {
            return this.last("LIMIT " + count);
        }
        return this;
    }

    /**
     * LIMIT start,count
     *
     * @param count      返回个数
     * @return
     */
    public Query<T> limit(int start, int count) {
        return this.last("LIMIT " + start + "," + count);
    }

    /**
     * last
     *
     * @param sql       SQL语句
     * @return
     */
    @Override
    public Query<T> last(String sql) {
        return this.last(true, sql);
    }

    /**
     * last
     *
     * @param condition
     * @param sql        SQL语句，可以通过{0},{1}来占位
     * @return
     */
    @Override
    public Query<T> last(boolean condition, String sql) {
        super.last(condition, sql);
        return this;
    }

    /**
     * first
     *
     * @param sql       SQL语句
     * @return
     */
    @Override
    public Query<T> first(String sql) {
        return this.first(true, sql);
    }

    /**
     * first
     *
     * @param condition
     * @param sql        SQL语句，可以通过{0},{1}来占位
     * @return
     */
    @Override
    public Query<T> first(boolean condition, String sql) {
        super.first(condition, sql);
        return this;
    }

    /**
     * order by asc
     *
     * @param column
     * @return
     */
    @Override
    public Query<T> orderByAsc(String column) {
        super.orderByAsc(column);
        return this;
    }

    /**
     * order by desc
     *
     * @param column
     * @return
     */
    @Override
    public Query<T> orderByDesc(String column) {
        super.orderByDesc(column);
        return this;
    }

    /**
     * order by sort asc
     *
     * @return
     */
    public Query<T> sort(){
        return this.orderByAsc(MapperConstant.FieldName.SORT);
    }

    /**
     * order by id asc
     *
     * @return
     */
    public Query<T> ascId(){
        return this.orderByAsc(MapperConstant.FieldName.ID);
    }

    /**
     * order by id desc
     *
     * @return
     */
    public Query<T> descId(){
        return this.orderByDesc(MapperConstant.FieldName.ID);
    }

    /**
     * order by create_time desc
     *
     * @return
     */
    public Query<T> descCreateTime(){
        return this.orderByDesc(MapperConstant.ColumnName.CREATE_TIME);
    }

    /**
     * order by update_time desc
     *
     * @return
     */
    public Query<T> descUpdateTime(){
        return this.orderByDesc(MapperConstant.ColumnName.UPDATE_TIME);
    }

    /**
     * group by
     *
     * @param column
     * @return
     */
    @Override
    public Query<T> groupBy(String column) {
        super.groupBy(column);
        return this;
    }

    /**
     * group by
     *
     * @param columns
     * @return
     */
    @Override
    public Query<T> groupBy(List<String> columns) {
        if (this.supportHumpParam && columns.size() > 1) {
            super.groupBy(columns.stream().map(this::columnToString).collect(Collectors.toList()));
        }else{
            super.groupBy(columns);
        }
        return this;
    }

    /**
     * 清除排序
     *
     * @return
     */
    public Query<T> clearOrder(){
        this.getExpression().getOrderBy().clear();
        return this;
    }

    /**
     * 清除分组
     *
     * @return
     */
    public Query<T> clearGroup(){
        this.getExpression().getGroupBy().clear();
        return this;
    }

    /**
     * 克隆
     *
     * 注意：无法复用query来替换、清除条件，只能clone或重建
     *
     * @return
     */
    public Query<T> clone(){
        return SerializationUtils.clone(this);
    }




    /**
     * 条件处理
     *
     * @param val   如果为null或''
     * @return
     */
    private static boolean condition(Object val){
        if (val == null) {
            return false;
        }
        return !(val instanceof String) || !((String) val).isEmpty();
    }

    /**
     * 参数名处理
     *
     * @param column
     *
     * @return 如果supportHumpParam，将xxXX 转 xx_xx
     */
    @Override
    protected String columnToString(String column) {
        if (this.supportHumpParam) {
            return StringUtil.parseHumpToLine(column);
        }
        return column;
    }

}
